home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-12-12 | 31.3 KB | 1,736 lines | [TEXT/KAHL] |
- /***
- *
- * Compiler.cp - bytecode compiler
- *
- * Original code: Copyright (c) 1991, by David Michael Betz. All rights reserved
- * Modified by Christopher E. Hyde, 1995
- *
- ***/
-
- #include "Bob.h"
- #include "Compiler.h"
-
-
- #if qDebug
- #define qDebugCompiler 0
- #define qDebugMem 0
- #else
- #define qDebugCompiler 0
- #define qDebugMem 0
- #endif
-
- // BranchHereFrom - fix up a forward reference
- #define BranchHereFrom(i) _CWordAt(i) = cptr
- //#define BranchHereFrom(i) FixUp(i)
- #define _PutByte(b) cbuff[cptr++] = b
- #define _CheckCodeSpace() { if (cptr >= kMaxCode) NoCodeSpace(); }
- #define _CWordAt(i) (*(CWord*) &cbuff[i])
-
- // Limits
- enum {
- kMaxCode = kCodeSize - 8, // allow for some overflow
- kMaxTempMem = 4 * 1024
- };
-
- // Variable access function codes
- enum { kLoad, kStore, kPush, kDup };
-
- // Partial value structure
- struct PVal {
- void (*fFn)(int, int);
- int fVal;
-
- inline void Load (void) const { (*fFn)(kLoad, fVal); }
- inline void Store (void) const { (*fFn)(kStore, fVal); }
- inline void Push (void) const { (*fFn)(kPush, 0); }
- inline void Dup (void) const { (*fFn)(kDup, 0); }
- inline void ClearFn (void) { fFn = nil; }
- };
-
- // Function argument structure
- struct TArgument {
- char* fName; // argument name
- TArgument* fNext; // next argument
- };
-
- // Literal structure
- struct TLiteral {
- TValue fValue; // literal value
- TLiteral* fNext; // next literal
- };
-
- typedef TArgument* TArgPtr;
- typedef TLiteral* TLitPtr;
- typedef int _Code;
- typedef int _CWord;
- typedef CWord KWord;
-
- // Local variables
- static TArgPtr arguments; // argument list
- static TArgPtr temporaries; // temporary variable list
- static TLitPtr literals = nil; // literal list
- static TValue methodclass; // class of the current method
- static CodePtr cbuff; // code buffer
- static _CWord cptr; // code pointer
- static Ptr pTempMem = nil, pNextMem = nil;
-
- // Break/continue stacks
- static KWord bstack[kMaxLoops], *bsp;
- static KWord cstack[kMaxLoops], *csp;
-
- // External variables
- extern TValue symbols; // symbol table
- extern TValue classes; // class table
- extern Value sp; // stack pointer
- #if qDebug
- extern KStr TypeName (int type);
- #endif
-
- // Forward declarations
- static void DoClass (void);
- static Entry FindMember (Class aClass, KStr name);
- static Entry RFindMember (Class aClass, KStr name);
- static void DoFunction (KStr name);
- static void DoRegularFunction(KStr name);
- static void DoMemberFunction(Value aClass);
- static Vector DoCode (KStr name, Value aClass);
- static Class GetClass (KStr name);
- static void DoStatement (void);
- static void DoIf (void);
- static KWord* AddBreak (int lbl);
- static _CWord RemBreak (KWord* old, CWord lbl);
- static KWord* AddContinue (int lbl);
- static void RemContinue (KWord* old);
- static void DoWhile (void);
- static void DoDoWhile (void);
- static void DoFor (void);
- static void DoBreak (void);
- static void DoContinue (void);
- static void DoBlock (void);
- static void DoReturn (void);
- static void DoTest (void);
- static void DoExpr (void);
- static void RValue (PVal* pv);
- static void CheckLValue (PVal* pv);
- static void DoExpr1 (PVal* pv);
- static void DoExpr2 (PVal* pv);
- static void DoAssignment (PVal* pv, int op);
- static void DoExpr3 (PVal* pv);
- static void DoExpr4 (PVal* pv);
- static void DoExpr5 (PVal* pv);
- static void DoExpr6 (PVal* pv);
- static void DoExpr7 (PVal* pv);
- static void DoExpr8 (PVal* pv);
- static void DoExpr9 (PVal* pv);
- static void DoExpr10 (PVal* pv);
- static void DoExpr11 (PVal* pv);
- static void DoExpr12 (PVal* pv);
- static void DoExpr13 (PVal* pv);
- static void DoExpr14 (PVal* pv);
- static void DoPreincrement (PVal* pv, int op);
- static void DoPostincrement (PVal* pv, int op);
- static void DoNew (PVal* pv);
- static void DoExpr15 (PVal* pv);
- static void DoPrimary (PVal* pv);
- static void DoCall (PVal* pv);
- static void DoSend (KStr selector, PVal* pv);
- static void DoIndex (PVal* pv);
- static int GetIdList (TArgPtr& list, KStr term);
- static void AddArgument (TArgPtr& list, KStr name);
- static void FreeList (TArgPtr& plist);
- static int FindArg (KStr name);
- static int FindTemp (KStr name);
- static Entry FindDataMember (KStr name);
- static int AddLiteral (TLitPtr& pval);
- static void FreeLiterals (TLitPtr& plist);
- static void FRequireId (TId id = nil);
- static void FRequire (TToken rtkn);
- static void Require (TToken tkn, TToken rtkn);
- static void DoLitInteger (long n);
- static void DoLitString (void);
- static int MakeLitString (KStr str);
- static int MakeLitVariable (Entry sym);
- static void FindVariable (KStr id, PVal* pv);
- static bool FindClassVar (Class aClass, KStr name, PVal* pv);
- static void CodeArgument (int fcn, int n);
- static void CodeTemporary (int fcn, int n);
- static void CodeMember (int fcn, int n);
- static void CodeVariable (int fcn, int n);
- static void CodeIndex (int fcn, int n);
- static void CodeLiteral (int n);
- static void PutCByte (_Code b);
- static void Put2CByte (_Code a, _Code b);
- static _CWord BranchForward (_Code op);
- static _CWord PutOpAndWord (_Code op, CWord w);
- static void FixUp (_CWord chain);
- static char* copystring (KStr str);
- static void* GetMemory (int size);
- static void FreeAll (void);
-
- inline static void CopyIdTo (TId id) { strcpy(id, gTokStr); };
- // Free a list of arguments or temporaries
- inline static void FreeList (TArgPtr& plist) { plist = nil; }
- // Free a list of literals
- inline static void FreeLiterals (void) { literals = nil; }
- #if !qDebugMem
- inline static void FreeAll (void) { pNextMem = pTempMem; }
- #endif
-
-
- // Initialize the compiler
- void
- InitCompiler (void)
- {
- literals = nil;
- set_nil(&methodclass);
- cbuff = (CodePtr) Calloc(kCodeSize, sizeof(Code));
- pNextMem = pTempMem = (Ptr) Calloc(1, kMaxTempMem);
- }
-
-
- // Mark compiler variables
- void
- MarkCompiler (void)
- {
- // if (cbuff) {
- for (TLitPtr lit = literals; lit != nil; lit = lit->fNext)
- Mark(&lit->fValue);
- Mark(&methodclass);
- // }
- }
-
-
- // Compile class or function definitions
- void
- CompileDefinitions (CIStream& iStream)
- {
- // Initialize
- InitScanner(iStream);
- bsp = &bstack[-1];
- csp = &cstack[-1];
-
- // Process statements until end of file
- TToken tkn;
- while ((tkn = Token()) != kEOF) {
- switch (tkn) {
- case kIdentifier:
- TId name;
- CopyIdTo(name);
- DoFunction(name);
- break;
- case kClass:
- DoClass();
- break;
- default:
- ParseError("Expecting a declaration");
- break;
- }
- }
- // EndScanner();
- // EndCompiler();
- }
-
-
- // Handle class declarations
- static void
- DoClass (void)
- {
- TArgPtr mvars, smvars, fargs;
-
- // Initialize
- mvars = smvars = fargs = nil;
- check(1);
-
- // Get the class name
- TId cname;
- FRequireId(cname);
-
- // Get the optional base class
- TToken tkn;
- TId id;
- if ((tkn = Token()) == ':') {
- FRequireId();
- push_class(GetClass(gTokStr));
- Info("Class ‘%s’, Base class ‘%s’",
- cname, GetCString(id, sizeof(id), clgetname(sp)));
- } else {
- push_nil();
- SaveToken(tkn);
- Info("Class ‘%s’", cname);
- }
- FRequire('{');
-
- // Create the new class object
- set_class(sp, NewClass(cname, sp));
- AddEntry(&classes, cname, stClass)->fValue = *sp;
-
- // handle each variable declaration
- while ((tkn = Token()) != '}') {
- // check for static members
- TToken type = tkn;
- if (type == kStatic)
- tkn = Token();
-
- // get the first identifier
- if (tkn != kIdentifier)
- ParseError("Expecting a member declaration");
- CopyIdTo(id);
-
- // check for a member function declaration
- if ((tkn = Token()) == '(') {
- GetIdList(fargs, ")");
- FRequire(')');
- AddEntry(clgetfunctions(sp), id,
- type == kStatic ? stSFunction : stFunction);
- FreeList(fargs);
- } else { // handle data members
- TArgPtr& table = (type == kStatic ? smvars : mvars);
- AddArgument(table, id);
- if (tkn == ',')
- GetIdList(table, ";");
- else
- SaveToken(tkn);
- }
- FRequire(';');
- }
-
- // Store the member variable names
- int i = isnil(clgetbase(sp)) ? 0 : clgetsize(clgetbase(sp));
- for (TArgPtr p = mvars; p != nil; p = p->fNext) {
- Entry entry = AddEntry(clgetmembers(sp), p->fName, stData);
- set_integer(&entry->fValue, i++);
- }
- sp->fClass->cl_size = i;
- FreeList(mvars);
-
- // Store the static member variable names
- for (p = smvars; p != nil; p = p->fNext)
- AddEntry(clgetmembers(sp), p->fName, stSData);
- FreeList(smvars);
- ++sp;
- FreeAll();
- }
-
-
- // Find a class member
- static Entry
- FindMember (Class aClass, KStr name)
- {
- Entry entry;
-
- if ((entry = FindEntry(&aClass->cl_members, name)) != nil)
- return entry;
- return FindEntry(&aClass->cl_functions, name);
- }
-
-
- // Recursive FindMember
- static Entry
- RFindMember (Class aClass, KStr name)
- {
- Entry entry;
-
- if ((entry = FindMember(aClass, name)) != nil)
- return entry;
- else if (!isnil(&aClass->cl_base))
- return RFindMember(claddr(&aClass->cl_base), name);
- return nil;
- }
-
-
- // Handle function declarations
- static void
- DoFunction (KStr name)
- {
- switch (Token()) {
- case '(':
- DoRegularFunction(name);
- break;
- case kCC:
- check(1);
- push_class(GetClass(name));
- DoMemberFunction(sp);
- ++sp;
- break;
- default:
- ParseError("Expecting a function declaration");
- break;
- }
- }
-
-
- // Parse a regular function definition
- static void
- DoRegularFunction (KStr name)
- {
- // enter the function name
- Info("Function ‘%s’", name);
- check(1);
- push_var(AddEntry(&symbols, name, stSFunction));
-
- // compile the body of the function
- set_bytecode(&sp->fVar->fValue, DoCode(name, &gNil));
- ++sp;
-
- // free the argument and temporary symbol lists
- FreeList(arguments); FreeList(temporaries);
- FreeAll();
- }
-
-
- // Parse a member function definition
- static void
- DoMemberFunction (Value aClass)
- {
- // get the selector
- TId name, selector;
- FRequireId(selector);
- FRequire('(');
- GetCString(name, sizeof(name), clgetname(aClass));
- Info("Member function ‘%s::%s’", name, selector);
-
- // make sure the type matches the declaration
- Entry entry;
- if ((entry = FindMember(claddr(aClass), selector)) != nil
- && entry->fType != stFunction
- && entry->fType != stSFunction)
- ParseError("Illegal redefinition");
-
- // compile the code
- check(1);
- push_var(AddEntry(clgetfunctions(aClass), selector, stFunction));
- set_bytecode(&sp->fVar->fValue, DoCode(selector, aClass));
- ++sp;
-
- // free the argument and temporary symbol lists
- FreeList(arguments); FreeList(temporaries);
- FreeAll();
- }
-
-
- // Compile the code part of a function or method
- static Vector
- DoCode (KStr name, Value aClass)
- {
- int tcnt = 0;
-
- // Initialize
- arguments = temporaries = nil;
- cptr = 0;
-
- // Add the implicit 'this' argument for member functions
- if (!isnil(aClass))
- AddArgument(arguments, "this");
- methodclass = *aClass;
-
- // Get the argument list
- GetIdList(arguments, ";)");
-
- // Get temporary variables
- TToken tkn;
- if ((tkn = Token()) == ';') {
- tcnt = GetIdList(temporaries, ")");
- tkn = Token();
- }
- Require(tkn, ')');
-
- // Reserve space for the temporaries
- if (tcnt > 0)
- Put2CByte(opTSPC, tcnt);
-
- // Store the bytecodes, class and function name as the first literals
- TLitPtr lit;
- AddLiteral(lit); // will become the bytecode string
- AddLiteral(lit); // class
- lit->fValue = *aClass;
- MakeLitString(name); // function name
-
- // Compile the code
- PutCByte(opPUSH);
- FRequire('{');
- DoBlock();
- PutCByte(opRTS);
-
- // Count the number of literals
- int nlits = 0;
- for (lit = literals; lit != nil; lit = lit->fNext)
- ++nlits;
-
- // Build the function
- check(1);
- push_bytecode(NewVector(nlits));
-
- // Create the code string
- set_string(&literals->fValue, NewString(cptr));
- memcpy(SData(&literals->fValue), cbuff, cptr);
-
- // Copy the literals
- lit = literals;
- for (int i = 0; i < nlits; ++i, lit = lit->fNext)
- VItem(sp, i) = lit->fValue;
-
- #if qDebugCompiler
- // Dump the literals
- lit = literals->fNext;
- for (i = 1; i < nlits; ++i, lit = lit->fNext) {
- PrintErrF("%2d: %s -> ", i, TypeName(lit->fValue.fType));
- if (lit->fValue.fType == tString)
- PrintErrF("%X ", lit->fValue.fStr);
- Print(&stderr_iostream, true, &lit->fValue);
- PrintErrF("\r");
- }
- // PrintErrF("\r");
- #endif
- FreeLiterals();
-
- // Show the generated code
- if (Opt(DumpCode))
- DumpProcedure(sp);
-
- // Return the code object
- return vecaddr(sp++);
- }
-
-
- // Get the class associated with a symbol
- static Class
- GetClass (KStr name)
- {
- Entry sym = FindEntry(&classes, name);
-
- if (sym == nil || sym->fValue.fType != tClass)
- ParseError("Expecting a class name");
- return claddr(&sym->fValue);
- }
-
-
- // Compile a single statement
- static void
- DoStatement (void)
- {
- TToken tkn;
- switch (tkn = Token()) {
- case kIf: DoIf(); break;
- case kWhile: DoWhile(); break;
- case kDo: DoDoWhile(); break;
- case kFor: DoFor(); break;
- case kBreak: DoBreak(); break;
- case kContinue: DoContinue(); break;
- case kReturn: DoReturn(); break;
- case '{': DoBlock(); break;
- case ';': break;
- default: SaveToken(tkn);
- DoExpr();
- FRequire(';'); break;
- }
- }
-
-
- // Compile the IF/ELSE expression
- static void
- DoIf (void)
- {
- // compile the test expression
- DoTest();
-
- // skip around the 'then' clause if the expression is false
- _CWord next = BranchForward(opBRF);
-
- // compile the 'then' clause
- DoStatement();
-
- // compile the 'else' clause
- TToken tkn;
- if ((tkn = Token()) == kElse) {
- _CWord end = BranchForward(opBR);
- BranchHereFrom(next);
- DoStatement();
- next = end;
- } else
- SaveToken(tkn);
-
- // handle the end of the statement
- BranchHereFrom(next);
- }
-
-
- // Add a break level to the stack
- static KWord*
- AddBreak (int lbl)
- {
- KWord* old = bsp;
- if (++bsp < &bstack[kMaxLoops])
- *bsp = lbl;
- else
- ParseError("Too many nested loops");
- return old;
- }
-
-
- // Remove a break level from the stack
- //static _CWord
- static int
- RemBreak (KWord* old, CWord lbl)
- {
- return bsp > old ? *bsp-- : lbl;
- }
-
-
- // Add a continue level to the stack
- static KWord*
- AddContinue (int lbl)
- {
- KWord* old = csp;
- if (++csp < &cstack[kMaxLoops])
- *csp = lbl;
- else
- ParseError("Too many nested loops");
- return old;
- }
-
-
- // Remove a continue level from the stack
- static void
- RemContinue (KWord* old)
- {
- csp = old;
- }
-
-
- // Compile the WHILE expression
- static void
- DoWhile (void)
- {
- // compile the test expression
- _CWord nxt = cptr;
- DoTest();
-
- // skip around the loop body if the expression is false
- _CWord end = BranchForward(opBRF);
-
- // compile the loop body
- KWord* ob = AddBreak(end);
- KWord* oc = AddContinue(nxt);
- DoStatement();
- end = RemBreak(ob, end);
- RemContinue(oc);
-
- // branch back to the start of the loop
- PutOpAndWord(opBR, nxt);
-
- // handle the end of the statement
- FixUp(end);
- }
-
-
- // Compile the DO/WHILE expression
- static void
- DoDoWhile (void)
- {
- // remember the start of the loop
- _CWord nxt = cptr;
-
- // compile the loop body
- KWord* ob = AddBreak(0);
- KWord* oc = AddContinue(nxt);
- DoStatement();
- CWord end = 0;
- end = RemBreak(ob, end);
- RemContinue(oc);
-
- // compile the test expression
- FRequire(kWhile);
- DoTest();
- FRequire(';');
-
- // branch to the top if the expression is true
- PutOpAndWord(opBRT, nxt);
-
- // handle the end of the statement
- FixUp(end);
- }
-
-
- // Compile the FOR statement
- static void
- DoFor (void)
- {
- // compile the initialization expression
- FRequire('(');
- TToken tkn;
- if ((tkn = Token()) != ';') {
- SaveToken(tkn);
- DoExpr();
- FRequire(';');
- }
-
- // compile the test expression
- CWord nxt = cptr;
- if ((tkn = Token()) != ';') {
- SaveToken(tkn);
- DoExpr();
- FRequire(';');
- }
-
- // branch to the loop body if the expression is true
- _CWord body = BranchForward(opBRT);
-
- // branch to the end if the expression is false
- _CWord end = BranchForward(opBR);
-
- // compile the update expression
- CWord update = cptr;
- if ((tkn = Token()) != ')') {
- SaveToken(tkn);
- DoExpr();
- FRequire(')');
- }
-
- // branch back to the test code
- PutOpAndWord(opBR, nxt);
-
- // compile the loop body
- FixUp(body);
- KWord* ob = AddBreak(end);
- KWord* oc = AddContinue(update);
- DoStatement();
- end = RemBreak(ob, end);
- RemContinue(oc);
-
- // branch back to the update code
- PutOpAndWord(opBR, update);
-
- // handle the end of the statement
- FixUp(end);
- }
-
-
- // Compile the BREAK statement
- static void
- DoBreak (void)
- {
- if (bsp < bstack)
- ParseError("Break outside of loop");
- *bsp = PutOpAndWord(opBR, *bsp);
- }
-
-
- // Compile the CONTINUE statement
- static void
- DoContinue (void)
- {
- if (csp < cstack)
- ParseError("Continue outside of loop");
- PutOpAndWord(opBR, *csp);
- }
-
-
- // Compile the {} expression
- static void
- DoBlock (void)
- {
- TToken tkn;
- if ((tkn = Token()) != '}') {
- do {
- SaveToken(tkn);
- DoStatement();
- } while ((tkn = Token()) != '}');
- } else
- PutCByte(opNIL);
- }
-
-
- // Handle the RETURN expression
- static void
- DoReturn (void)
- {
- DoExpr();
- FRequire(';');
- PutCByte(opRTS);
- }
-
-
- // Compile a test expression
- static void
- DoTest (void)
- {
- FRequire('(');
- DoExpr();
- FRequire(')');
- }
-
-
- // Parse an expression
- static void
- DoExpr (void)
- {
- PVal pv;
-
- DoExpr1(&pv);
- RValue(&pv);
- }
-
-
- // Get the rvalue of a partial expression
- static void
- RValue (PVal* pv)
- {
- if (pv->fFn) {
- pv->Load();
- pv->ClearFn();
- }
- }
-
-
- // Make sure we've got an lvalue
- static void
- CheckLValue (PVal* pv)
- {
- if (pv->fFn == nil)
- ParseError("Expecting an lvalue");
- }
-
-
- // Handle the ',' operator
- static void
- DoExpr1 (PVal* pv)
- {
- TToken tkn;
- DoExpr2(pv);
- while ((tkn = Token()) == ',') {
- RValue(pv);
- DoExpr1(pv); RValue(pv);
- }
- SaveToken(tkn);
- }
-
-
- // Handle the assignment operators
- static void
- DoExpr2 (PVal* pv)
- {
- #if ((kADDEQ + 9) != kSHREQ)
- #error "kADDEQ + 9 != kSHREQ"
- #endif
- #if ((opADD + 9) != opSHR)
- #error "opADD + 9 != opSHR"
- #endif
-
- DoExpr3(pv);
- while (1) {
- TToken tkn = Token();
- if (tkn == '=') {
- CheckLValue(pv);
- pv->Push();
- PVal rhs;
- DoExpr1(&rhs); RValue(&rhs);
- pv->Store();
- } else if (tkn >= kADDEQ && tkn <= kSHLEQ) {
- CheckLValue(pv);
- DoAssignment(pv, tkn - kADDEQ + opADD);
- } else {
- SaveToken(tkn);
- break;
- }
- pv->ClearFn();
- }
- }
-
-
- // Handle assignment operations
- static void
- DoAssignment (PVal* pv, int op)
- {
- pv->Dup();
- pv->Load();
- PutCByte(opPUSH);
-
- PVal rhs;
- DoExpr1(&rhs); RValue(&rhs);
- PutCByte(op);
- pv->Store();
- }
-
-
- // Handle the '?:' operator
- static void
- DoExpr3 (PVal* pv)
- {
- TToken tkn;
- DoExpr4(pv);
- while ((tkn = Token()) == '?') {
- RValue(pv);
- _CWord nxt = BranchForward(opBRF);
- DoExpr1(pv); RValue(pv);
- FRequire(':');
- _CWord end = BranchForward(opBR);
- FixUp(nxt);
- DoExpr1(pv); RValue(pv);
- FixUp(end);
- }
- SaveToken(tkn);
- }
-
-
- // Handle the '||' operator
- static void
- DoExpr4 (PVal* pv)
- {
- TToken tkn;
- _CWord end = 0;
- DoExpr5(pv);
- while ((tkn = Token()) == kOR) {
- RValue(pv);
- end = PutOpAndWord(opBRT, end);
- DoExpr5(pv); RValue(pv);
- }
- FixUp(end);
- SaveToken(tkn);
- }
-
-
- // Handle the '&&' operator
- static void
- DoExpr5 (PVal* pv)
- {
- TToken tkn;
- _CWord end = 0;
- DoExpr6(pv);
- while ((tkn = Token()) == kAND) {
- RValue(pv);
- end = PutOpAndWord(opBRF, end);
- DoExpr6(pv); RValue(pv);
- }
- FixUp(end);
- SaveToken(tkn);
- }
-
-
- // Handle the '|' operator
- static void
- DoExpr6 (PVal* pv)
- {
- TToken tkn;
- DoExpr7(pv);
- while ((tkn = Token()) == '|') {
- RValue(pv);
- PutCByte(opPUSH);
- DoExpr7(pv); RValue(pv);
- PutCByte(opBOR);
- }
- SaveToken(tkn);
- }
-
-
- // Handle the '^' operator
- static void
- DoExpr7 (PVal* pv)
- {
- TToken tkn;
- DoExpr8(pv);
- while ((tkn = Token()) == '^') {
- RValue(pv);
- PutCByte(opPUSH);
- DoExpr8(pv); RValue(pv);
- PutCByte(opXOR);
- }
- SaveToken(tkn);
- }
-
-
- // Handle the '&' operator
- static void
- DoExpr8 (PVal* pv)
- {
- TToken tkn;
- DoExpr9(pv);
- while ((tkn = Token()) == '&') {
- RValue(pv);
- PutCByte(opPUSH);
- DoExpr9(pv); RValue(pv);
- PutCByte(opBAND);
- }
- SaveToken(tkn);
- }
-
-
- // Handle the '==' and '!=' operators
- static void
- DoExpr9 (PVal* pv)
- {
- #if 1
- DoExpr10(pv);
- while (1) {
- TToken tkn = Token();
- _Code op;
- if (tkn == kEQ)
- op = opEQ;
- else if (tkn == kNE)
- op = opNE;
- else {
- SaveToken(tkn);
- break;
- }
- RValue(pv);
- PutCByte(opPUSH);
- DoExpr10(pv); RValue(pv);
- PutCByte(op);
- }
- #else
- DoExpr10(pv);
- while (1) {
- TToken tkn = Token();
- _Code op;
- switch (tkn) {
- case kEQ: op = opEQ; break;
- case kNE: op = opNE; break;
- default: SaveToken(tkn); return;
- }
- RValue(pv);
- PutCByte(opPUSH);
- DoExpr10(pv); RValue(pv);
- PutCByte(op);
- }
- #endif
- }
-
-
- // Handle the '<', '<=', '>=' and '>' operators
- static void
- DoExpr10 (PVal* pv)
- {
- DoExpr11(pv);
- while (1) {
- TToken tkn = Token();
- _Code op;
- switch (tkn) {
- case '<': op = opLT; break;
- case kLE: op = opLE; break;
- case kGE: op = opGE; break;
- case '>': op = opGT; break;
- default: SaveToken(tkn); return;
- }
- RValue(pv);
- PutCByte(opPUSH);
- DoExpr11(pv); RValue(pv);
- PutCByte(op);
- }
- }
-
-
- // Handle the '<<' and '>>' operators
- static void
- DoExpr11 (PVal* pv)
- {
- DoExpr12(pv);
- while (1) {
- TToken tkn = Token();
- _Code op;
- if (tkn == kSHL)
- op = opSHL;
- else if (tkn == kSHR)
- op = opSHR;
- else {
- SaveToken(tkn);
- break;
- }
- RValue(pv);
- PutCByte(opPUSH);
- DoExpr12(pv); RValue(pv);
- PutCByte(op);
- }
- }
-
-
- // Handle the '+' and '-' operators
- static void
- DoExpr12 (PVal* pv)
- {
- DoExpr13(pv);
- while (1) {
- TToken tkn = Token();
- _Code op;
- if (tkn == '+')
- op = opADD;
- else if (tkn == '-')
- op = opSUB;
- else {
- SaveToken(tkn);
- break;
- }
- RValue(pv);
- PutCByte(opPUSH);
- DoExpr13(pv); RValue(pv);
- PutCByte(op);
- }
- }
-
-
- // Handle the '*', '/' and '%' operators
- static void
- DoExpr13 (PVal* pv)
- {
- DoExpr14(pv);
- while (1) {
- TToken tkn = Token();
- _Code op;
- switch (tkn) {
- case '*': op = opMUL; break;
- case '/': op = opDIV; break;
- case '%': op = opREM; break;
- default: SaveToken(tkn); return;
- }
- RValue(pv);
- PutCByte(opPUSH);
- DoExpr14(pv); RValue(pv);
- PutCByte(op);
- }
- }
-
-
- // Handle unary operators
- static void
- DoExpr14 (PVal* pv)
- {
- TToken tkn;
- switch (tkn = Token()) {
- case '-':
- DoExpr15(pv); RValue(pv);
- PutCByte(opNEG);
- break;
- case '!':
- DoExpr15(pv); RValue(pv);
- PutCByte(opNOT);
- break;
- case '~':
- DoExpr15(pv); RValue(pv);
- PutCByte(opBNOT);
- break;
- case kINC:
- DoPreincrement(pv, opINC);
- break;
- case kDEC:
- DoPreincrement(pv, opDEC);
- break;
- case kNew:
- DoNew(pv);
- break;
- default:
- SaveToken(tkn);
- DoExpr15(pv);
- return;
- }
- }
-
-
- // Handle prefix '++' and '--'
- static void
- DoPreincrement (PVal* pv, int op)
- {
- DoExpr15(pv);
- CheckLValue(pv);
- pv->Dup();
- pv->Load();
- PutCByte(op);
- pv->Store();
- pv->ClearFn();
- }
-
-
- // Handle postfix '++' and '--'
- static void
- DoPostincrement (PVal* pv, int op)
- {
- CheckLValue(pv);
- pv->Dup();
- pv->Load();
- PutCByte(op);
- pv->Store();
- PutCByte(op == opINC ? opDEC : opINC);
- pv->ClearFn();
- }
-
-
- // Handle the 'new' operator
- static void
- DoNew (PVal* pv)
- {
- TId selector;
- FRequireId(selector);
- Class aClass = GetClass(selector);
-
- TLitPtr lit;
- CodeLiteral(AddLiteral(lit));
- set_class(&lit->fValue, aClass);
-
- PutCByte(opNEW);
- pv->ClearFn();
-
- DoSend(selector, pv);
- }
-
-
- // Handle function calls
- static void
- DoExpr15 (PVal* pv)
- {
- DoPrimary(pv);
- while (1) {
- TToken tkn = Token();
- switch (tkn) {
- case '(':
- DoCall(pv);
- break;
- case '[':
- DoIndex(pv);
- break;
- case kMemRef:
- TId selector;
- FRequireId(selector);
- DoSend(selector, pv);
- break;
- case kINC:
- DoPostincrement(pv, opINC);
- break;
- case kDEC:
- DoPostincrement(pv, opDEC);
- break;
- default:
- SaveToken(tkn);
- return;
- }
- }
- }
-
-
- // Parse a primary expression and unary operators
- static void
- DoPrimary (PVal* pv)
- {
- TId id;
- Entry entry;
- Class aClass;
- TToken tkn;
-
- switch (Token()) {
- case '(':
- DoExpr1(pv);
- FRequire(')');
- break;
- case kNumber:
- DoLitInteger((long) gTokVal);
- pv->ClearFn();
- break;
- case kString:
- DoLitString();
- pv->ClearFn();
- break;
- case kNil:
- PutCByte(opNIL);
- pv->ClearFn();
- break;
- case kIdentifier:
- CopyIdTo(id);
- if ((tkn = Token()) == kCC) {
- aClass = GetClass(id);
- FRequireId();
- if (!FindClassVar(aClass, gTokStr, pv))
- ParseError("Not a class member");
- }
- else {
- SaveToken(tkn);
- FindVariable(id, pv);
- }
- break;
- default:
- ParseError("Expecting a primary expression");
- break;
- }
- }
-
-
- // Compile a function call
- static void
- DoCall (PVal* pv)
- {
- TToken tkn;
- int n = 0;
-
- // get the value of the function
- RValue(pv);
-
- // compile each argument expression
- if ((tkn = Token()) != ')') {
- SaveToken(tkn);
- do {
- PutCByte(opPUSH);
- DoExpr2(pv); RValue(pv);
- ++n;
- } while ((tkn = Token()) == ',');
- }
- Require(tkn, ')');
- Put2CByte(opCALL, n);
-
- // we've got an rvalue now
- pv->ClearFn();
- }
-
-
- // Compile a message sending expression
- static void
- DoSend (KStr selector, PVal* pv)
- {
- // get the receiver value
- RValue(pv);
-
- // generate code to push the selector
- PutCByte(opPUSH);
- #if 0
- TLitPtr lit;
- CodeLiteral(AddLiteral(lit));
- set_string(&lit->fValue, MakeString(selector));
- #else
- CodeLiteral(MakeLitString(selector));
- #endif
-
- // compile the argument list
- TToken tkn;
- int n = 1;
- FRequire('(');
- if ((tkn = Token()) != ')') {
- SaveToken(tkn);
- do {
- PutCByte(opPUSH);
- DoExpr2(pv); RValue(pv);
- ++n;
- } while ((tkn = Token()) == ',');
- }
- Require(tkn, ')');
-
- // send the message
- Put2CByte(opSEND, n);
-
- // we've got an rvalue now
- pv->ClearFn();
- }
-
-
- // Compile an indexing operation
- static void
- DoIndex (PVal* pv)
- {
- RValue(pv);
- PutCByte(opPUSH);
- DoExpr();
- FRequire(']');
- pv->fFn = CodeIndex;
- }
-
-
- // Get a comma separated list of identifiers
- static int
- GetIdList (TArgPtr& list, KStr term)
- {
- int count = 0;
- TToken tkn = Token();
- if (!strchr(term, tkn)) {
- SaveToken(tkn);
- do {
- FRequireId();
- AddArgument(list, gTokStr);
- ++count;
- } while ((tkn = Token()) == ',');
- }
- SaveToken(tkn);
- return count;
- }
-
-
- // Add a formal argument
- static void
- AddArgument (TArgPtr& list, KStr name)
- {
- TArgPtr arg = (TArgPtr) GetMemory(sizeof(TArgument));
- arg->fName = copystring(name);
- arg->fNext = list;
- list = arg;
- }
-
-
- // Find an argument offset
- static int
- FindArg (KStr name)
- {
- TArgPtr arg = arguments;
-
- for (int n = 0; arg; n++, arg = arg->fNext)
- if (strcmp(name, arg->fName) == 0)
- return n;
- return -1;
- }
-
-
- // Find a temporary variable offset
- static int
- FindTemp (KStr name)
- {
- TArgPtr tmp = temporaries;
-
- for (int n = 0; tmp; n++, tmp = tmp->fNext)
- if (strcmp(name, tmp->fName) == 0)
- return n;
- return -1;
- }
-
-
- #if 0
- // Find a class data member
- static Entry
- FindDataMember (KStr name)
- {
- Entry entry;
- Value aClass;
-
- if (!isnil(&methodclass)) {
- aClass = &methodclass;
- do {
- if ((entry = FindEntry(clgetmembers(aClass), name)) != nil)
- return entry;
- aClass = clgetbase(aClass);
- } while (!isnil(aClass));
- }
- return nil;
- }
- #endif
-
-
- // Add a literal
- static int
- AddLiteral (TLitPtr& pval)
- {
- int n = 0;
- for (TLitPtr* plit = &literals; *plit != nil; plit = &(*plit)->fNext)
- ++n;
- TLitPtr lit = (TLitPtr) GetMemory(sizeof(TLiteral));
- set_nil(&lit->fValue);
- lit->fNext = nil;
- pval = *plit = lit;
- return n;
- }
-
-
- // Fetch a token and require it to be an id
- static void
- FRequireId (TId id)
- {
- Require(Token(), kIdentifier);
- if (id)
- CopyIdTo(id);
- }
-
-
- // Fetch a token and check it
- static void
- FRequire (TToken rtkn)
- {
- Require(Token(), rtkn);
- }
-
-
- // Check for a required token
- static void
- Require (TToken token, TToken rtkn)
- {
- if (token != rtkn) {
- char msg[100], tknbuf[16];
-
- strcpy(tknbuf, TokenName(rtkn));
- sprintf(msg, "Expecting '%s', found '%s'", tknbuf, TokenName(token));
- ParseError(msg);
- }
- }
-
-
- // Compile a literal integer
- static void
- DoLitInteger (long n)
- {
- if (n >= SHRT_MIN && n <= SHRT_MAX) {
- PutOpAndWord(opINT, n);
- } else {
- TLitPtr lit;
- CodeLiteral(AddLiteral(lit));
- set_integer(&lit->fValue, n);
- }
- }
-
-
- // Compile a literal string
- static void
- DoLitString (void)
- {
- TLitPtr lit;
- int n = AddLiteral(lit);
- set_string(&lit->fValue, MakeString(gTokStr, gTokVal));
- CodeLiteral(n);
- }
-
-
- // Make a literal string
- static int
- MakeLitString (KStr str)
- {
- TLitPtr lit;
- int n = AddLiteral(lit);
- set_string(&lit->fValue, MakeString(str));
- return n;
- }
-
-
- // Make a literal reference to a variable
- static int
- MakeLitVariable (Entry sym)
- {
- #if 0
- int i = 0;
- for (TLitPtr p = literals; p != nil; p = p->fNext) {
- if (p->fValue.fType == tVar && p->fValue.fVar == sym) {
- PrintErrF("Found variable %d ‘", n);
- Print(&stderr_iostream, true, &p->fValue);
- PrintErrF("’ at %d\r", i);
- }
- ++i;
- }
- #endif
-
- int n = 0;
- for (TLitPtr lit = literals; lit != nil; ++n, lit = lit->fNext)
- if (lit->fValue.fType == tVar && lit->fValue.fVar == sym)
- return n;
- n = AddLiteral(lit);
- set_var(&lit->fValue, sym);
- return n;
- }
-
-
- // Find a variable
- static void
- FindVariable (KStr id, PVal* pv)
- {
- int n;
- if ((n = FindArg(id)) >= 0) {
- pv->fFn = CodeArgument;
- pv->fVal = n;
- } else if ((n = FindTemp(id)) >= 0) {
- pv->fFn = CodeTemporary;
- pv->fVal = n;
- } else if (isnil(&methodclass)
- || !FindClassVar(claddr(&methodclass), id, pv)) {
- pv->fFn = CodeVariable;
- pv->fVal = MakeLitVariable(AddEntry(&symbols, id, stSData));
- }
- }
-
-
- // Find a class member variable
- static bool
- FindClassVar (Class aClass, KStr name, PVal* pv)
- {
- Entry entry;
- if ((entry = RFindMember(aClass, name)) == nil)
- return false;
- switch (entry->fType) {
- case stData:
- pv->fFn = CodeMember;
- pv->fVal = entry->fValue.fInt;
- break;
- case stSData:
- pv->fFn = CodeVariable;
- pv->fVal = MakeLitVariable(entry);
- break;
- case stFunction:
- FindVariable("this", pv);
- DoSend(name, pv);
- break;
- case stSFunction:
- CodeVariable(kLoad, MakeLitVariable(entry));
- pv->ClearFn();
- break;
- }
- return true;
- }
-
-
- // Compile an argument reference
- static void
- CodeArgument (int fcn, int n)
- {
- switch (fcn) {
- case kLoad: Put2CByte(opAREF, n); break;
- case kStore: Put2CByte(opASET, n); break;
- }
- }
-
-
- // Compile a temporary variable reference
- static void
- CodeTemporary (int fcn, int n)
- {
- switch (fcn) {
- case kLoad: Put2CByte(opTREF, n); break;
- case kStore: Put2CByte(opTSET, n); break;
- }
- }
-
-
- // Compile a data member reference
- static void
- CodeMember (int fcn, int n)
- {
- switch (fcn) {
- case kLoad: Put2CByte(opMREF, n); break;
- case kStore: Put2CByte(opMSET, n); break;
- }
- }
-
-
- // Compile a variable reference
- static void
- CodeVariable (int fcn, int n)
- {
- switch (fcn) {
- case kLoad: Put2CByte(opREF, n); break;
- case kStore: Put2CByte(opSET, n); break;
- }
- }
-
-
- // Compile an indexed reference
- static void
- CodeIndex (int fcn, int n)
- {
- switch (fcn) {
- case kLoad: PutCByte(opVREF); break;
- case kStore: PutCByte(opVSET); break;
- case kPush: PutCByte(opPUSH); break;
- case kDup: PutCByte(opDUP2); break;
- }
- }
-
-
- // Compile a literal reference
- static void
- CodeLiteral (int n)
- {
- Put2CByte(opLIT, n);
- }
-
-
- static void
- NoCodeSpace (void)
- {
- ParseError("Insufficient code space");
- }
-
-
- // Put a code byte into data space
- static void
- PutCByte (_Code b)
- {
- _PutByte(b);
- _CheckCodeSpace();
- }
-
-
- // Put 2 bytes into data space
- static void
- Put2CByte (_Code a, _Code b)
- {
- _PutByte(a);
- _PutByte(b);
- _CheckCodeSpace();
- }
-
-
- // Put an opcode and a 0 word into code space. Return offset of 0 word
- static _CWord
- BranchForward (_Code op)
- {
- _PutByte(op);
- _CWordAt(cptr) = 0;
- cptr += 2;
- _CheckCodeSpace();
- return cptr - 2;
- }
-
-
- // Put an opcode and a data word into code space. Return offset of data word
- static _CWord
- PutOpAndWord (_Code op, CWord w)
- {
- _PutByte(op);
- _CWordAt(cptr) = w;
- cptr += 2;
- _CheckCodeSpace();
- return cptr - 2;
- }
-
-
- // Fix up a reference chain
- static void
- FixUp (_CWord chain)
- {
- for (_CWord next; chain; chain = next) {
- next = _CWordAt(chain);
- _CWordAt(chain) = cptr;
- }
- }
-
-
- // Make a copy of a string
- static char*
- copystring (KStr str)
- {
- char* s = (char*) GetMemory(strlen(str) + 1);
- strcpy(s, str);
- return s;
- }
-
-
- #if qDebugMem
- static int pMemCount = 0;
- #endif
-
-
- // Allocate memory and complain if there isn't enough
- static void*
- GetMemory (int size)
- {
- size = (size + (sizeof(SInt32) - 1)) & ~(sizeof(SInt32) - 1);
- #if qDebugMem
- if (Opt(Debug))
- PrintErrF("\t\tMem used = %d\r", pMemCount += size);
- #endif
-
- void* ptr = pNextMem;
- pNextMem += size;
-
- if (pNextMem > &pTempMem[kMaxTempMem])
- Error("Insufficient memory");
- return ptr;
- }
-
-
- #if qDebugMem
- static void
- FreeAll (void)
- {
- if (Opt(Debug)) {
- PrintErrF("\t\tTotal mem used = %d\r", pMemCount);
- pMemCount = 0;
- }
-
- pNextMem = pTempMem;
- }
- #endif
-